//
// Copyright 2007-2009 Taglab Limited.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.taglab.chic.support;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * Utility class to read a JSP into a String (after it has been interpreted
 * by the servlet container) without making a HTTP request.
 * <p>
 * A typical usage is to use a JSP to generate the message body for
 * sending emails, without using a different template language such as
 * FreeMarker or Velocity.
 * <p>
 * Note that JSPs generating binary output are not currently supported.
 * (More specifically only <code>response.writer</code> is supported,
 * not <code>response.outputStream</code>.)
 */
public class JspTemplate {

  private final HttpServletRequest request;
  private final HttpServletResponse response;

  public JspTemplate(HttpServletRequest request, HttpServletResponse response) {
    this.request = request;
    this.response = response;
  }

  public String process(String templatePath, Map<String,String> parameters) throws ServletException, IOException {
    RequestWrapper requestWrapper = new RequestWrapper(request);
    requestWrapper.setParameters(parameters);
    ResponseWrapper responseWrapper = new ResponseWrapper(response);
    RequestDispatcher dispatcher = request.getRequestDispatcher(templatePath);
    dispatcher.include(requestWrapper, responseWrapper);
    return responseWrapper.getBody();
  } 

  private class RequestWrapper extends HttpServletRequestWrapper {
        
    private Map<String,String> parameters = new HashMap<String,String>();
    
    public RequestWrapper(HttpServletRequest request) {
      super(request);
    }

    public void setParameters(Map<String,String> attributes) {
      this.parameters = attributes;
    }

    @Override
    public String getParameter(String name) {
      return parameters.get(name);
    }
  }

  private class ResponseWrapper extends HttpServletResponseWrapper {

    private StringWriter stringWriter = new StringWriter();

    private int status = 200;

    public ResponseWrapper(HttpServletResponse response) {
      super(response);
    }

    @Override
    public PrintWriter getWriter() {
      return new PrintWriter(stringWriter);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
      throw new UnsupportedOperationException("only getWriter() is supported by this ResponseWrapper");
    }

    @Override
    public void setContentType(String contentType) {
      // ignore
    }

    @Override
    public void setLocale(Locale locale) {
      // ignore
    }

    @Override
    public void setStatus(int status) {
      this.status = status;
    }

    public int getStatus() {
      return status;
    }

    public String getBody() {
      return stringWriter.toString();
    }
  }

}
